
// <copyright file="Generic_Pool_Tests_With_Shared_Objects.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The generic_ pool_ tests_ with_ shared_ objects.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Tests.Pooling
{
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Threading;
    using System.Threading.Tasks;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// The generic_ pool_ tests_ with_ shared_ objects.
    /// </summary>
    [TestClass]
    public class Generic_Pool_Tests_With_Shared_Objects
    {
        #region Public Methods and Operators

        /// <summary>
        /// The pool asynchronous test.
        /// </summary>
        [TestMethod]
        public void PoolAsynchronousTest()
        {
            const int maxPoolSize = 1000;
            const int objectMaxIdleTimeInMilliseconds = 5000;

            var pool = new ConnectionPool { CanObjectBeShared = true, MaxPoolSize = maxPoolSize, ObjectMaxIdleTimeInMilliseconds = objectMaxIdleTimeInMilliseconds };

            var bag = new ConcurrentBag<DummyConnectionWrapper>();
            var e = new CountdownEvent(10);
            for (int i = 0; i < maxPoolSize; i += 100)
            {
                Task.Factory.StartNew(state =>
                    {
                        var kvp = (KeyValuePair<int, int>)state;
                        for (int j = kvp.Key; j < kvp.Value; j++)
                        {
                            var connection = pool.GetConnection(kvp.Key.ToString(CultureInfo.InvariantCulture)) as DummyConnectionWrapper;
                            bag.Add(connection);
                        }

                        e.Signal();
                    }, new KeyValuePair<int, int>(i, i + 100));
            }

            e.Wait();
            Assert.IsTrue(pool.Count == 10);
            var dictionary = new Dictionary<IConnection, int>();
            foreach (DummyConnectionWrapper v in bag)
            {
                int count = 0;
                if (dictionary.TryGetValue(v.AdaptedObject, out count))
                {
                    dictionary[v.AdaptedObject] = count + 1;
                }
                else
                {
                    dictionary.Add(v.AdaptedObject, 1);
                }
            }

            Assert.IsTrue(dictionary.Count == 10);
        }

        /// <summary>
        /// The pool synchronous test.
        /// </summary>
        [TestMethod]
        public void PoolSynchronousTest()
        {
            const int maxPoolSize = 10;
            const int objectMaxIdleTimeInMilliseconds = 5000;

            var pool = new ConnectionPool { CanObjectBeShared = true, MaxPoolSize = maxPoolSize, ObjectMaxIdleTimeInMilliseconds = objectMaxIdleTimeInMilliseconds };
            var connection1 = (DummyConnectionWrapper)pool.GetConnection("1");
            var connection2 = (DummyConnectionWrapper)pool.GetConnection("1");

            Assert.IsTrue(pool.Count == 1);
            Assert.IsTrue(connection1.ConnectionString == connection2.ConnectionString);
            Assert.IsTrue(ReferenceEquals(connection1.AdaptedObject, connection2.AdaptedObject));

            var connection3 = (DummyConnectionWrapper)pool.GetConnection("2");
            Assert.IsTrue(connection1.ConnectionString != connection3.ConnectionString);
            Assert.IsTrue(!ReferenceEquals(connection1.AdaptedObject, connection3.AdaptedObject));
            Assert.IsTrue(pool.Count == 2);

            // Lets Dispose connection2
            connection2.Dispose();
            Assert.IsTrue(pool.Count == 2);
            Assert.IsTrue(connection1.ConnectionString == "1");

            connection2 = (DummyConnectionWrapper)pool.GetConnection("1");
            Assert.IsTrue(connection1.ConnectionString == connection2.ConnectionString);
            Assert.IsTrue(ReferenceEquals(connection1.AdaptedObject, connection2.AdaptedObject));

            connection3.Dispose();
            Thread.Sleep(pool.ObjectMaxIdleTimeInMilliseconds + 100);
            Assert.IsTrue(pool.Count == 1);
        }

        #endregion Public Methods and Operators
    }
}
